package njiandan.mvc.core;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import njiandan.mvc.annotation.MultipartConfig; 
import njiandan.mvc.utils.GetArgumentName;

class ActionConfig {
	/**
	 * 声明的内置变量
	 */
	static final Class<?>[] builtInObjects = { HttpServletRequest.class,
			HttpServletResponse.class, HttpSession.class, Cookie.class };

	/**
	 * Object instance.
	 */
	final Object instance;

	/**
	 * Method instance.
	 */
	final Method actionMethod;

	final boolean isMultipartAction;

	final MultipartConfig multipartConfig;
	/**
	 * Method's arguments' types.
	 */
	final Class<?>[] argumentTypes;

	/**
     * 
     */
	final int[] urlArgumentOrder;

	/**
	 * Method's arguments' names.
	 */
	final List<String> argumentNames;

	/**
	 * 参数注射器
	 */
	final Map<String, ParameterInjector> injectors = new HashMap<String, ParameterInjector>();

	List<BilidInArgumentInfo> builtInArguments = null;

	ActionConfig(Object instance, Method actionMethod, int[] urlArgumentOrder) {
		this.instance = instance;
		this.actionMethod = actionMethod;
		this.argumentTypes = actionMethod.getParameterTypes();
		this.argumentNames = GetArgumentName.getArgumentNames(actionMethod);		
		this.urlArgumentOrder = urlArgumentOrder;

		if (actionMethod.getAnnotation(MultipartConfig.class) != null) {
			multipartConfig = actionMethod.getAnnotation(MultipartConfig.class);
			boolean is = true;
			if ("".equals(multipartConfig.attributeName())) {
				is = false;
			}

			if (multipartConfig.limitSize() <= 0) {
				is = false;
			}

			this.isMultipartAction = is;
		} else {
			this.isMultipartAction = false;
			multipartConfig = null;
		}

		

		/* 取消虚拟机安全检查，大幅提高方法调用效率 */
		this.actionMethod.setAccessible(true);
		initInjector();
	}

	/**
	 * 为action方法初始化参数注射器（请求参数->java Object）
	 * 
	 * TODO 如果一个方法已经被解析过，就不要在解析了，这种情况在一个方法配置多个url时发生
	 */
	private void initInjector() {
		ParameterInjector injector;
		Set<String> keys;
		Class<?> type;
		for (int i = 0; i < argumentTypes.length; i++) {
			type = argumentTypes[i];
			/*
			 * 内置参数 包括Cookie数组、HttpServletRequest、HttpServletResponse、Session
			 */
			if (type.equals(Cookie.class) || type.equals(Cookie[].class)
					|| type.equals(HttpSession.class)
					|| type.equals(HttpServletRequest.class)
					|| type.equals(HttpServletResponse.class)) {
				if (builtInArguments == null) {
					builtInArguments = new ArrayList<BilidInArgumentInfo>();
				}
				builtInArguments.add(new BilidInArgumentInfo(i, argumentNames
						.get(i), type));

				continue;
			}

			injector = new ParameterInjector(i, type, argumentNames.get(i));
			keys = injector.getKeys();
			for (String key : keys) {
				injectors.put(key, injector);
			}
		}
	}
}